/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package argentracker.activeentity.property;

import java.util.HashMap;
import java.util.Map;

import argentracker.activeentity.ActiveEntity;
import argentracker.activeentity.P;
import argentracker.activeentity.exceptions.ActiveEntityException;

/**
 * briefly description.
 * 
 * extense description.
 * 
 * @author matero (matero _at_ gmail _dot_ com)
 */
public class EnumProperty<T extends Enum<T>, AE extends ActiveEntity<AE>> extends P<T, AE> {

    private final T[] constants;
    private final Map<Object, T> constantsByName;
    private final Integer traductedDefaultValue;

    /**
     * Constructs an enum property with no name and <code>null</code> as default value.
     */
    public EnumProperty(Class<T> enumType) {
        this(enumType, NO_NAME, null);
    }

    /**
     * Construts an enum property defining its name, and setting <code>null</code> as default value.
     * 
     * @param propertyName
     */
    public EnumProperty(Class<T> enumType, String propertyName) {
        this(enumType, propertyName, null);
    }

    /**
     * Constructs an Integer property defining its name and default value.
     * 
     * @param propertyName
     */
    public EnumProperty(Class<T> enumType, String propertyName, T propertyDefaultValue) {
        super(enumType, propertyName, propertyDefaultValue);
        constants = enumType.getEnumConstants();
        constantsByName = new HashMap<Object, T>();
        for (T constant : constants) {
            constantsByName.put(constant.name(), constant);
        }
        traductedDefaultValue = propertyDefaultValue == null ? null : propertyDefaultValue.ordinal();
    }

    @Override
    @SuppressWarnings("unchecked")
    public T interpret(Object value) {
        if (getType().equals(value.getClass())) {
            return (T) value;
        }

        if (value instanceof String) {
            return constantsByName.get(value);
        }

        if (value instanceof Number) {
            Number number = (Number) value;
            return constants[number.intValue()];
        }

        throw new ActiveEntityException("illegal value class, expected one of [" + getType().getName()
                + ", String, Number] received [" + value.getClass().getName() + "].");
    }

    @Override
    public Object traduct(T value) {
        return value == null ? traductedDefaultValue : value.ordinal();
    }

}
